package com.ledtechdesign.afcs;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ledtechdesign.auth.AuthenticationFactory;
import com.ledtechdesign.beans.Account;
import com.ledtechdesign.beans.Item;
import com.ledtechdesign.beans.Session;
import com.ledtechdesign.beans.api.IAccountInfo;
import com.ledtechdesign.beans.api.IMeetingInfo;
import com.ledtechdesign.beans.api.IMeetingInfoDescriptor;
import com.ledtechdesign.beans.api.IRepository;
import com.ledtechdesign.service.ContainerType;
import com.ledtechdesign.service.IAFCSService;
import com.ledtechdesign.service.ServiceManagerEnum;
import com.ledtechdesign.service.Utils;
import com.ledtechdesign.service.api.IAFCSServiceResult;

public class AccountManager {

	private static AccountManager instaince;

	public Account account;
	private String username;
	private String password;
	private SessionInfo accountSessionInfo;

	private Authenticator authenticator = null;

	private Map<String, String> authHeaders = new HashMap<String, String>();
	public IAuthToken authToken;
	Log logger = LogFactory.getLog(this.getClass().getName());

	private IAFCSService<? extends IAFCSServiceResult> service;

	// private String baseURL = null;
	// private String contentPath = null;
	// private String roomInstance = null;

	
	public AccountManager(String propertyFilename,Account account, ServiceManagerEnum serviceType)
	throws Exception {
		this(Utils.loadProperties(propertyFilename),account,serviceType);
	}
	
	public AccountManager(Properties props,Account account, ServiceManagerEnum serviceType)
	throws Exception {
		this.account = account;
		this.service = serviceType.get(this.account);
		// TODO fix this.
		this.account.setSecret(props.getProperty("afcs.devSecret"));
		this.username = props.getProperty("afcs.devUserName");
		this.password = props.getProperty("afcs.devPassword");
		
		String authURL = this.service.preInitializationService(this.account);
		this.authenticator = new Authenticator(authURL);
	}

	/*
	 * Login into account
	 */
	public void loginAsGuest(String guest) throws Exception {
		String token= this.authenticator.guestLogin(guest);
		this.authToken =AuthenticationFactory.getGuestAuthToken(token);
		this.logger.debug("Token (guest): " + this.authToken);
		this.do_initialize(this.authToken);
	}

	public void login() throws Exception {
		
		String globalSessionString = this.authenticator.login(username, password,
				this.authHeaders);
		accountSessionInfo = new SessionInfo(globalSessionString);
	 this.authToken = AuthenticationFactory.getAuthToken(globalSessionString);
				
			
			this.logger.debug("Token (user): " + this.authToken);
		this.do_initialize(this.authToken);
	}

	public void do_initialize(IAuthToken authToken) throws Exception {
		IMeetingInfoDescriptor mi;
		mi = this.service.initializationService(authToken, this.account);
		String contentPath = mi.getAccountPath();
		String roomInstance = mi.getRoomInstanceURL();
		this.account.setUrl(mi.getBaseURL());
		String acctid[] = contentPath.split("/");
		logger.debug("Array lastIndexOf " + acctid[acctid.length - 1]);
		this.account.init(acctid[acctid.length - 1], contentPath, roomInstance);
	}

	public ISession getSession(String roomName) throws Exception {
		// String[] parts = this.url.split("/");
		// roomInstanceString.replaceAll("#room#", roomName);
		String roomInstanceURI = this.account.getRoomInstanceString()
				.replaceAll("#room#", roomName);
		
//		if(this.authToken.isGuest()){
//			this.login();
//		}
		
		// TODO maybe make it Lazy?
		String sessionSecret = this.service.fetchSessionSecret(authToken,
				roomInstanceURI);

		Session session = new Session(this.account, sessionSecret,
				roomInstanceURI, roomName);
		return session;
	}

	/*
	 * Create room
	 */
	public IMeetingInfoDescriptor createRoom(String room) {
		return this.createRoom(room, null);
	}

	// public static AccountManager getInstance() {
	//		 
	// return null;
	// }

	public IMeetingInfoDescriptor createRoom(String room, String template) {
		IMeetingInfoDescriptor result;
		try {
			result = this.service.createRoom(this.authToken, room, template);
			return result;
		} catch (Exception e) {
			// e.printStackTrace();
			// TODO Should throw E hee.
			this.logger.error("\n\r Could not Create room " + room
					+ " maybe room already exists");
			return null;
		}
	}

	public IMeetingInfoDescriptor createTemplate(String name, String basedOn) {
		IMeetingInfoDescriptor result;
		try {
			result = this.service.createTemplate(this.authToken, name, basedOn);
			return result;
		} catch (Exception e) {
			// e.printStackTrace();
			// TODO Should throw E here.
			this.logger.error("\n\r Could not Create template " + name
					+ " maybe room already exists");
			return null;
		}
	}

	/*
	 * delete room or template
	 */
	public IRepository delete(String item) {
		return this.delete(item, null);
	}

	public IRepository delete(String item, ContainerType containerType) {
		IRepository result;
		try {
			result = this.service.delete(this.authToken, item, containerType);
			return result;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			this.logger.error(e.getMessage());

			this.logger.error("\n\r Could not Delete item " + item
					+ " maybe item does not exists");
			return null;

		}
	}

	/*
	 * Delete room
	 */
	public IRepository deleteRoom(String item) {
		try {
			IRepository result = this.service.deleteRoom(this.authToken, item);
			return result;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			this.logger.debug(e.getMessage());

			this.logger.error("\n\r Could not Delete room " + item
					+ " maybe item does not exists");
			return null;
		}
	}

	/*
	 * Delete template
	 */
	public IRepository deleteTemplate(String item) throws Exception {

		try {
			IRepository result = this.service.deleteTemplate(this.authToken,
					item);
			return result;
		} catch (Exception e) {
			// TODO throw Exception
			this.logger.debug(e.getMessage());

			this.logger.error("\n\r Could not Delete template " + item
					+ " maybe item does not exists");
			return null;
		}

	}

	/*
	 * return info about the account, if active
	 */
	public IAccountInfo getAccountInfo() throws Exception {
		// TODO see TODO in Account line:41
		// TODO check for NPE getRoomInstanceString

		IAccountInfo result = this.service.getAccountInfo(this.authToken);
		return result;
	}

	String getContentURL() {
		return this.account.getUrl() + IAFCSService.contentAppSegment
				+ this.account.getAccountPath();
	}

	/*
	 * return the AFCS nodes @ path
	 */
	public String getNodes(String room, String path) throws Exception {
		// TODO NOT WORKING FOR NOW.
		IAFCSServiceResult result = this.service.getNodes(this.authToken, room,
				path);
		return result.toString();
	}

	/*
	 * return info about the room/instance, if active
	 */
	public IMeetingInfo getRoomInfo(String room) throws Exception {
		IMeetingInfo result;
		try {
			result = this.service.getRoomInfo(this.authToken, room);
			return result;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
			this.logger.debug(e.getMessage());

			this.logger.error("\n\r Could nto get info for room " + room
					+ " maybe room does not exist");
			return null;
		}
	}

	public IAFCSService<? extends IAFCSServiceResult> getService() {
		return this.service;
	}

	/*
	 * List rooms or templates
	 */
	public List<Item> listItems() throws Exception {
		// default to room
		return this.listItems(ContainerType.ROOM);
		// return listItems(null);
	}

	public List<Item> listItems(ContainerType containerType) throws Exception {
		return this.service.listItems(this.authToken, containerType);
	}

	/*
	 * List rooms
	 */
	public List<Item> listRooms() throws Exception {
		return this.listItems(IAFCSService.ROOM_ITEMS);
	}

	/*
	 * List templates
	 */
	public List<Item> listTemplates() throws Exception {
		return this.listItems(IAFCSService.TEMPLATE_ITEMS);
	}
	
	private class SessionInfo {
		
		private final String delimeter="\\*";
		private String oringinalString;
		
		private Properties properties;
		
		public SessionInfo(String sessionString){
			properties = new Properties();
			String[] props = sessionString.split(delimeter);
			for (int i = 0; i < props.length; i++) {
				String key = props[i];
				String value = props[++i];
				System.out.println("i="+key +" value "+value);
				
				properties.setProperty(key, value);
			}
		}
		
		public String toString () { 
			return oringinalString;
		}
		
	}

}
